home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / terms / tip / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-28  |  16.3 KB  |  876 lines

  1. /*
  2.  * Copyright (c) 1983 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)cmds.c    5.8 (Berkeley) 9/2/88";
  20. #endif /* not lint */
  21.  
  22. #include "tip.h"
  23. /*
  24.  * tip
  25.  *
  26.  * miscellaneous commands
  27.  */
  28.  
  29. int    quant[] = { 60, 60, 24 };
  30.  
  31. char    null = '\0';
  32. char    *sep[] = { "second", "minute", "hour" };
  33. static char *argv[10];        /* argument vector for take and put */
  34.  
  35. sigfunc_t    timeout();    /* timeout function called on alarm */
  36. sigfunc_t    stopsnd();    /* SIGINT handler during file transfers */
  37. sigfunc_t    intprompt();    /* used in handling SIG_INT during prompt */
  38. sigfunc_t    intcopy();    /* interrupt routine for file transfers */
  39.  
  40. /*
  41.  * FTP - remote ==> local
  42.  *  get a file from the remote host
  43.  */
  44. getfl(c)
  45.     char c;
  46. {
  47.     char buf[256], *cp, *expand();
  48.     
  49.     putchar(c);
  50.     /*
  51.      * get the UNIX receiving file's name
  52.      */
  53.     if (prompt("Local file name? ", copyname))
  54.         return;
  55.     cp = expand(copyname);
  56.     if ((sfd = creat(cp, 0666)) < 0) {
  57.         printf("\r\n%s: cannot creat\r\n", copyname);
  58.         return;
  59.     }
  60.     
  61.     /*
  62.      * collect parameters
  63.      */
  64.     if (prompt("List command for remote system? ", buf)) {
  65.         unlink(copyname);
  66.         return;
  67.     }
  68.     transfer(buf, sfd, value(EOFREAD));
  69. }
  70.  
  71. /*
  72.  * Cu-like take command
  73.  */
  74. /*ARGUSED*/
  75. cu_take(cc)
  76.     char cc;
  77. {
  78.     int fd, argc;
  79.     char line[BUFSIZ], *expand(), *cp;
  80.  
  81.     if (prompt("[take] ", copyname))
  82.         return;
  83.     if ((argc = args(copyname, argv)) < 1 || argc > 2) {
  84.         printf("usage: <take> from [to]\r\n");
  85.         return;
  86.     }
  87.     if (argc == 1)
  88.         argv[1] = argv[0];
  89.     cp = expand(argv[1]);
  90.     if ((fd = creat(cp, 0666)) < 0) {
  91.         printf("\r\n%s: cannot create\r\n", argv[1]);
  92.         return;
  93.     }
  94.     sprintf(line, "cat %s;echo \01", argv[0]);
  95.     transfer(line, fd, "\01");
  96. }
  97.  
  98. static    jmp_buf intbuf;
  99. /*
  100.  * Bulk transfer routine --
  101.  *  used by getfl(), cu_take(), and pipefile()
  102.  */
  103. transfer(buf, fd, eofchars)
  104.     char *buf, *eofchars;
  105. {
  106.     register int ct;
  107.     char c, buffer[BUFSIZ];
  108.     register char *p = buffer;
  109.     register int cnt, eof;
  110.     time_t start;
  111.     sigfunc_t (*f)();
  112.  
  113.     pwrite(FD, buf, size(buf));
  114.     quit = 0;
  115.     kill(pid, SIGIOT);
  116.     read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
  117.     
  118.     /*
  119.      * finish command
  120.      */
  121.     pwrite(FD, "\r", 1);
  122.     do
  123.         read(FD, &c, 1); 
  124.     while ((c&0177) != '\n');
  125.     ioctl(0, TIOCSETC, &defchars);
  126.     
  127.     (void) setjmp(intbuf);
  128.     f = signal(SIGINT, intcopy);
  129.     start = time(0);
  130.     for (ct = 0; !quit;) {
  131.         eof = read(FD, &c, 1) <= 0;
  132.         c &= 0177;
  133.         if (quit)
  134.             continue;
  135.           if (eof || any(c, eofchars))
  136.               break;
  137.         if (c == 0)
  138.             continue;    /* ignore nulls */
  139.         if (c == '\r')
  140.             continue;
  141.         *p++ = c;
  142.  
  143.         if (c == '\n' && boolean(value(VERBOSE)))
  144.             printf("\r%d", ++ct);
  145.         if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
  146.             if (write(fd, buffer, cnt) != cnt) {
  147.                 printf("\r\nwrite error\r\n");
  148.                 quit = 1;
  149.             }
  150.             p = buffer;
  151.         }
  152.     }
  153.     if (cnt = (p-buffer))
  154.         if (write(fd, buffer, cnt) != cnt)
  155.             printf("\r\nwrite error\r\n");
  156.  
  157.     if (boolean(value(VERBOSE)))
  158.         prtime(" lines transferred in ", time(0)-start);
  159.     ioctl(0, TIOCSETC, &tchars);
  160.     write(fildes[1], (char *)&ccc, 1);
  161.     signal(SIGINT, f);
  162.     close(fd);
  163. }
  164.  
  165. /*
  166.  * FTP - remote ==> local process
  167.  *   send remote input to local process via pipe
  168.  */
  169. pipefile()
  170. {
  171.     int cpid, pdes[2];
  172.     char buf[256];
  173.     int status, p;
  174.     extern int errno;
  175.  
  176.     if (prompt("Local command? ", buf))
  177.         return;
  178.  
  179.     if (pipe(pdes)) {
  180.         printf("can't establish pipe\r\n");
  181.         return;
  182.     }
  183.  
  184.     if ((cpid = fork()) < 0) {
  185.         printf("can't fork!\r\n");
  186.         return;
  187.     } else if (cpid) {
  188.         if (prompt("List command for remote system? ", buf)) {
  189.             close(pdes[0]), close(pdes[1]);
  190.             kill (cpid, SIGKILL);
  191.         } else {
  192.             sigfunc_t (*f)();
  193.  
  194.             close(pdes[0]);
  195.             f = signal(SIGPIPE, intcopy);
  196.             transfer(buf, pdes[1], value(EOFREAD));
  197.             signal(SIGPIPE, f);
  198.             while ((p = wait(&status)) > 0 && p != cpid)
  199.                 ;
  200.         }
  201.     } else {
  202.         register int f;
  203.  
  204.         dup2(pdes[0], 0);
  205.         close(pdes[0]);
  206.         for (f = 3; f < 20; f++)
  207.             close(f);
  208.         execute(buf);
  209.         printf("can't execl!\r\n");
  210.         exit(0);
  211.     }
  212. }
  213.  
  214. /*
  215.  * Interrupt service routine for FTP
  216.  */
  217. sigfunc_t
  218. stopsnd()
  219. {
  220.  
  221.     stop = 1;
  222.     signal(SIGINT, SIG_IGN);
  223. }
  224.  
  225. /*
  226.  * FTP - local ==> remote
  227.  *  send local file to remote host
  228.  *  terminate transmission with pseudo EOF sequence
  229.  */
  230. sendfile(cc)
  231.     char cc;
  232. {
  233.     FILE *fd;
  234.     char *fnamex;
  235.     char *expand();
  236.  
  237.     putchar(cc);
  238.     /*
  239.      * get file name
  240.      */
  241.     if (prompt("Local file name? ", fname))
  242.         return;
  243.  
  244.     /*
  245.      * look up file
  246.      */
  247.     fnamex = expand(fname);
  248.     if ((fd = fopen(fnamex, "r")) == NULL) {
  249.         printf("%s: cannot open\r\n", fname);
  250.         return;
  251.     }
  252.     transmit(fd, value(EOFWRITE), NULL);
  253.     if (!boolean(value(ECHOCHECK)) || boolean(value(LINESYNC))) {
  254.         struct sgttyb buf;
  255.  
  256.         ioctl(FD, TIOCGETP, &buf);    /* this does a */
  257.         ioctl(FD, TIOCSETP, &buf);    /*   wflushtty */
  258.     }
  259. }
  260.  
  261. /*
  262.  * Bulk transfer routine to remote host --
  263.  *   used by sendfile() and cu_put()
  264.  */
  265. transmit(fd, eofchars, command)
  266.     FILE *fd;
  267.     char *eofchars, *command;
  268. {
  269.     char *pc, lastc;
  270.     int c, ccount, lcount;
  271.     time_t start_t, stop_t;
  272.     sigfunc_t (*f)();
  273.  
  274.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  275.     stop = 0;
  276.     f = signal(SIGINT, stopsnd);
  277.     ioctl(0, TIOCSETC, &defchars);
  278.     read(repdes[0], (char *)&ccc, 1);
  279.     if (command != NULL) {
  280.         for (pc = command; *pc; pc++)
  281.             send(*pc);
  282.         if (boolean(value(ECHOCHECK)) || boolean(value(LINESYNC)))
  283.             read(FD, (char *)&c, 1);    /* trailing \n */
  284.         else {
  285.             struct sgttyb buf;
  286.  
  287.             ioctl(FD, TIOCGETP, &buf);    /* this does a */
  288.             ioctl(FD, TIOCSETP, &buf);    /*   wflushtty */
  289.             sleep(5); /* wait for remote stty to take effect */
  290.         }
  291.     }
  292.     lcount = 0;
  293.     lastc = '\0';
  294.     start_t = time(0);
  295.     while (1) {
  296.         ccount = 0;
  297.         do {
  298.             c = getc(fd);
  299.             if (stop)
  300.                 goto out;
  301.             if (c == EOF)
  302.                 goto out;
  303.             if (c == 0177 && !boolean(value(RAWFTP)))
  304.                 continue;
  305.             lastc = c;
  306.             if (c < 040) {
  307.                 if (c == '\n') {
  308.                     if (!boolean(value(RAWFTP)))
  309.                         c = '\r';
  310.                 }
  311.                 else if (c == '\t') {
  312.                     if (!boolean(value(RAWFTP))) {
  313.                         if (boolean(value(TABEXPAND))) {
  314.                             send(' ');
  315.                             while ((++ccount % 8) != 0)
  316.                                 send(' ');
  317.                             continue;
  318.                         }
  319.                     }
  320.                 } else
  321.                     if (!boolean(value(RAWFTP)))
  322.                         continue;
  323.             }
  324.             send(c);
  325.         } while (c != '\r' && !boolean(value(RAWFTP)));
  326.         if (boolean(value(VERBOSE)))
  327.             printf("\r%d", ++lcount);
  328.         if (boolean(value(ECHOCHECK)) || boolean(value(LINESYNC))) {
  329.             timedout = 0;
  330.             alarm(value(ETIMEOUT));
  331.             do {    /* wait for prompt */
  332.                 read(FD, (char *)&c, 1);
  333.                 if (timedout || stop) {
  334.                     if (timedout)
  335.                         printf("\r\ntimed out at eol\r\n");
  336.                     alarm(0);
  337.                     goto out;
  338.                 }
  339.             } while ((c&0177) != character(value(PROMPT)));
  340.             alarm(0);
  341.         }
  342.     }
  343. out:
  344.     if (lastc != '\n' && !boolean(value(RAWFTP)))
  345.         send('\r');
  346.     for (pc = eofchars; *pc; pc++)
  347.         send(*pc);
  348.     stop_t = time(0);
  349.     fclose(fd);
  350.     signal(SIGINT, f);
  351.     if (boolean(value(VERBOSE)))
  352.         if (boolean(value(RAWFTP)))
  353.             prtime(" chars transferred in ", stop_t-start_t);
  354.         else
  355.             prtime(" lines transferred in ", stop_t-start_t);
  356.     write(fildes[1], (char *)&ccc, 1);
  357.     ioctl(0, TIOCSETC, &tchars);
  358. }
  359.  
  360. /*
  361.  * Cu-like put command
  362.  */
  363. /*ARGUSED*/
  364. cu_put(cc)
  365.     char cc;
  366. {
  367.     FILE *fd;
  368.     char line[BUFSIZ];
  369.     int argc;
  370.     char *expand();
  371.     char *copynamex;
  372.  
  373.     if (prompt("[put] ", copyname))
  374.         return;
  375.     if ((argc = args(copyname, argv)) < 1 || argc > 2) {
  376.         printf("usage: <put> from [to]\r\n");
  377.         return;
  378.     }
  379.     if (argc == 1)
  380.         argv[1] = argv[0];
  381.     copynamex = expand(argv[0]);
  382.     if ((fd = fopen(copynamex, "r")) == NULL) {
  383.         printf("%s: cannot open\r\n", copynamex);
  384.         return;
  385.     }
  386.     if (boolean(value(ECHOCHECK)))
  387.         sprintf(line, "cat>%s\r", argv[1]);
  388.     else
  389.         sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
  390.     transmit(fd, "\04", line);
  391. }
  392.  
  393. /*
  394.  * FTP - send single character
  395.  *  wait for echo & handle timeout
  396.  */
  397. send(c)
  398.     char c;
  399. {
  400.     char cc;
  401.     int retry = 0;
  402.  
  403.     cc = c;
  404.     pwrite(FD, &cc, 1);
  405. #ifdef notdef
  406.     if (number(value(CDELAY)) > 0 && c != '\r')
  407.         nap(number(value(CDELAY)));
  408. #endif
  409.     if (!boolean(value(ECHOCHECK))) {
  410. #ifdef notdef
  411.         if (number(value(LDELAY)) > 0 && c == '\r')
  412.             nap(number(value(LDELAY)));
  413. #endif
  414.         return;
  415.     }
  416. tryagain:
  417.     timedout = 0;
  418.     alarm(value(ETIMEOUT));
  419.     read(FD, &cc, 1);
  420.     alarm(0);
  421.     if (timedout) {
  422.         printf("\r\ntimeout error (%s)\r\n", ctrl(c));
  423.         if (retry++ > 3)
  424.             return;
  425.         pwrite(FD, &null, 1); /* poke it */
  426.         goto tryagain;
  427.     }
  428. }
  429.  
  430. sigfunc_t
  431. timeout()
  432. {
  433.     signal(SIGALRM, timeout);
  434.     timedout = 1;
  435. }
  436.  
  437. /*
  438.  * Stolen from consh() -- puts a remote file on the output of a local command.
  439.  *    Identical to consh() except for where stdout goes.
  440.  */
  441. pipeout(c)
  442. {
  443.     char buf[256];
  444.     int cpid, status, p;
  445.     time_t start;
  446.  
  447.     putchar(c);
  448.     if (prompt("Local command? ", buf))
  449.         return;
  450.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  451.     signal(SIGINT, SIG_IGN);
  452.     signal(SIGQUIT, SIG_IGN);
  453.     ioctl(0, TIOCSETC, &defchars);
  454.     read(repdes[0], (char *)&ccc, 1);
  455.     /*
  456.      * Set up file descriptors in the child and
  457.      *  let it go...
  458.      */
  459.     if ((cpid = fork()) < 0)
  460.         printf("can't fork!\r\n");
  461.     else if (cpid) {
  462.         start = time(0);
  463.         while ((p = wait(&status)) > 0 && p != cpid)
  464.             ;
  465.     } else {
  466.         register int i;
  467.  
  468.         dup2(FD, 1);
  469.         for (i = 3; i < 20; i++)
  470.             close(i);
  471.         signal(SIGINT, SIG_DFL);
  472.         signal(SIGQUIT, SIG_DFL);
  473.         execute(buf);
  474.         printf("can't find `%s'\r\n", buf);
  475.         exit(0);
  476.     }
  477.     if (boolean(value(VERBOSE)))
  478.         prtime("away for ", time(0)-start);
  479.     write(fildes[1], (char *)&ccc, 1);
  480.     ioctl(0, TIOCSETC, &tchars);
  481.     signal(SIGINT, SIG_DFL);
  482.     signal(SIGQUIT, SIG_DFL);
  483. }
  484.  
  485. #ifdef CONNECT
  486. /*
  487.  * Fork a program with:
  488.  *  0 <-> local tty in
  489.  *  1 <-> local tty out
  490.  *  2 <-> local tty out
  491.  *  3 <-> remote tty in
  492.  *  4 <-> remote tty out
  493.  */
  494. consh(c)
  495. {
  496.     char buf[256];
  497.     int cpid, status, p;
  498.     time_t start;
  499.  
  500.     putchar(c);
  501.     if (prompt("Local command? ", buf))
  502.         return;
  503.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  504.     signal(SIGINT, SIG_IGN);
  505.     signal(SIGQUIT, SIG_IGN);
  506.     ioctl(0, TIOCSETC, &defchars);
  507.     read(repdes[0], (char *)&ccc, 1);
  508.     /*
  509.      * Set up file descriptors in the child and
  510.      *  let it go...
  511.      */
  512.     if ((cpid = fork()) < 0)
  513.         printf("can't fork!\r\n");
  514.     else if (cpid) {
  515.         start = time(0);
  516.         while ((p = wait(&status)) > 0 && p != cpid)
  517.             ;
  518.     } else {
  519.         register int i;
  520.  
  521.         dup2(FD, 3);
  522.         dup2(3, 4);
  523.         for (i = 5; i < 20; i++)
  524.             close(i);
  525.         signal(SIGINT, SIG_DFL);
  526.         signal(SIGQUIT, SIG_DFL);
  527.         execute(buf);
  528.         printf("can't find `%s'\r\n", buf);
  529.         exit(0);
  530.     }
  531.     if (boolean(value(VERBOSE)))
  532.         prtime("away for ", time(0)-start);
  533.     write(fildes[1], (char *)&ccc, 1);
  534.     ioctl(0, TIOCSETC, &tchars);
  535.     signal(SIGINT, SIG_DFL);
  536.     signal(SIGQUIT, SIG_DFL);
  537. }
  538. #endif
  539.  
  540. /*
  541.  * Escape to local shell
  542.  */
  543. shell()
  544. {
  545.     int shpid, status;
  546.     extern char **environ;
  547.     char *cp;
  548.  
  549.     printf("[sh]\r\n");
  550.     signal(SIGINT, SIG_IGN);
  551.     signal(SIGQUIT, SIG_IGN);
  552.     unraw();
  553.     if (shpid = fork()) {
  554.         while (shpid != wait(&status));
  555.         raw();
  556.         printf("\r\n!\r\n");
  557.         signal(SIGINT, SIG_DFL);
  558.         signal(SIGQUIT, SIG_DFL);
  559.         return;
  560.     } else {
  561.         signal(SIGQUIT, SIG_DFL);
  562.         signal(SIGINT, SIG_DFL);
  563.         if ((cp = rindex(value(SHELL), '/')) == NULL)
  564.             cp = value(SHELL);
  565.         else
  566.             cp++;
  567.         shell_uid();
  568.         execl(value(SHELL), cp, 0);
  569.         printf("\r\ncan't execl!\r\n");
  570.         exit(1);
  571.     }
  572. }
  573.  
  574. /*
  575.  * TIPIN portion of scripting
  576.  *   initiate the conversation with TIPOUT
  577.  */
  578. setscript()
  579. {
  580.     char c;
  581.     /*
  582.      * enable TIPOUT side for dialogue
  583.      */
  584.     kill(pid, SIGEMT);
  585.     if (boolean(value(SCRIPT)))
  586.         write(fildes[1], value(RECORD), size(value(RECORD)));
  587.     write(fildes[1], "\n", 1);
  588.     /*
  589.      * wait for TIPOUT to finish
  590.      */
  591.     read(repdes[0], &c, 1);
  592.     if (c == 'n')
  593.         printf("can't create %s\r\n", value(RECORD));
  594. }
  595.  
  596. /*
  597.  * Change current working directory of
  598.  *   local portion of tip
  599.  */
  600. chdirectory()
  601. {
  602.     char dirname[80];
  603.     register char *cp = dirname;
  604.  
  605.     if (prompt("[cd] ", dirname)) {
  606.         if (stoprompt)
  607.             return;
  608.         cp = value(HOME);
  609.     }
  610.     if (chdir(cp) < 0)
  611.         printf("%s: bad directory\r\n", cp);
  612.     printf("!\r\n");
  613. }
  614.  
  615. abort(msg)
  616.     char *msg;
  617. {
  618.  
  619.     kill(pid, SIGTERM);
  620.     disconnect(msg);
  621.     if (msg != NOSTR)
  622.         printf("\r\n%s", msg);
  623.     printf("\r\n[EOT]\r\n");
  624.     daemon_uid();
  625.     (void)uu_unlock(uucplock);
  626.     unraw();
  627.     exit(0);
  628. }
  629.  
  630. finish()
  631. {
  632.     char *dismsg;
  633.  
  634.     if ((dismsg = value(DISCONNECT)) != NOSTR) {
  635.         write(FD, dismsg, strlen(dismsg));
  636.         sleep(5);
  637.     }
  638.     abort(NOSTR);
  639. }
  640.  
  641. sigfunc_t
  642. intcopy()
  643. {
  644.  
  645.     raw();
  646.     quit = 1;
  647.     longjmp(intbuf, 1);
  648. }
  649.  
  650. execute(s)
  651.     char *s;
  652. {
  653.     register char *cp;
  654.  
  655.     if ((cp = rindex(value(SHELL), '/')) == NULL)
  656.         cp = value(SHELL);
  657.     else
  658.         cp++;
  659.     user_uid();
  660.     execl(value(SHELL), cp, "-c", s, 0);
  661. }
  662.  
  663. args(buf, a)
  664.     char *buf, *a[];
  665. {
  666.     register char *p = buf, *start;
  667.     register char **parg = a;
  668.     register int n = 0;
  669.  
  670.     do {
  671.         while (*p && (*p == ' ' || *p == '\t'))
  672.             p++;
  673.         start = p;
  674.         if (*p)
  675.             *parg = p;
  676.         while (*p && (*p != ' ' && *p != '\t'))
  677.             p++;
  678.         if (p != start)
  679.             parg++, n++;
  680.         if (*p)
  681.             *p++ = '\0';
  682.     } while (*p);
  683.  
  684.     return(n);
  685. }
  686.  
  687. prtime(s, a)
  688.     char *s;
  689.     time_t a;
  690. {
  691.     register i;
  692.     int nums[3];
  693.  
  694.     for (i = 0; i < 3; i++) {
  695.         nums[i] = (int)(a % quant[i]);
  696.         a /= quant[i];
  697.     }
  698.     printf("%s", s);
  699.     while (--i >= 0)
  700.         if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
  701.             printf("%d %s%c ", nums[i], sep[i],
  702.                 nums[i] == 1 ? '\0' : 's');
  703.     printf("\r\n!\r\n");
  704. }
  705.  
  706. variable()
  707. {
  708.     char    buf[256];
  709.  
  710.     if (prompt("[set] ", buf))
  711.         return;
  712.     vlex(buf);
  713.     if (vtable[BEAUTIFY].v_access&CHANGED) {
  714.         vtable[BEAUTIFY].v_access &= ~CHANGED;
  715.         kill(pid, SIGSYS);
  716.     }
  717.     if (vtable[SCRIPT].v_access&CHANGED) {
  718.         vtable[SCRIPT].v_access &= ~CHANGED;
  719.         setscript();
  720.         /*
  721.          * So that "set record=blah script" doesn't
  722.          *  cause two transactions to occur.
  723.          */
  724.         if (vtable[RECORD].v_access&CHANGED)
  725.             vtable[RECORD].v_access &= ~CHANGED;
  726.     }
  727.     if (vtable[RECORD].v_access&CHANGED) {
  728.         vtable[RECORD].v_access &= ~CHANGED;
  729.         if (boolean(value(SCRIPT)))
  730.             setscript();
  731.     }
  732.     if (vtable[TAND].v_access&CHANGED) {
  733.         vtable[TAND].v_access &= ~CHANGED;
  734.         if (boolean(value(TAND)))
  735.             tandem("on");
  736.         else
  737.             tandem("off");
  738.     }
  739.      if (vtable[LECHO].v_access&CHANGED) {
  740.          vtable[LECHO].v_access &= ~CHANGED;
  741.          HD = boolean(value(LECHO));
  742.      }
  743.     if (vtable[PARITY].v_access&CHANGED) {
  744.         vtable[PARITY].v_access &= ~CHANGED;
  745.         setparity();
  746.     }
  747. }
  748.  
  749. /*
  750.  * Turn tandem mode on or off for remote tty.
  751.  */
  752. tandem(option)
  753.     char *option;
  754. {
  755.     struct sgttyb rmtty;
  756.  
  757.     ioctl(FD, TIOCGETP, &rmtty);
  758.     if (strcmp(option,"on") == 0) {
  759.         rmtty.sg_flags |= TANDEM;
  760.         arg.sg_flags |= TANDEM;
  761.     } else {
  762.         rmtty.sg_flags &= ~TANDEM;
  763.         arg.sg_flags &= ~TANDEM;
  764.     }
  765.     ioctl(FD, TIOCSETP, &rmtty);
  766.     ioctl(0,  TIOCSETP, &arg);
  767. }
  768.  
  769. /*
  770.  * Send a break.
  771.  */
  772. genbrk()
  773. {
  774.  
  775.     ioctl(FD, TIOCSBRK, NULL);
  776.     sleep(1);
  777.     ioctl(FD, TIOCCBRK, NULL);
  778. }
  779.  
  780. /*
  781.  * Suspend tip
  782.  */
  783. suspend(c)
  784.     char c;
  785. {
  786.  
  787.     unraw();
  788.     kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
  789.     raw();
  790. }
  791.  
  792. /*
  793.  *    expand a file name if it includes shell meta characters
  794.  */
  795.  
  796. char *
  797. expand(name)
  798.     char name[];
  799. {
  800.     static char xname[BUFSIZ];
  801.     char cmdbuf[BUFSIZ];
  802.     register int pid, l;
  803.     register char *cp, *Shell;
  804.     int s, pivec[2];
  805.  
  806.     if (!anyof(name, "~{[*?$`'\"\\"))
  807.         return(name);
  808.     if (pipe(pivec) < 0) {
  809.         perror("pipe");
  810.         /* signal(SIGINT, sigint) */
  811.         return(name);
  812.     }
  813.     sprintf(cmdbuf, "echo %s", name);
  814.     if ((pid = vfork()) == 0) {
  815.         Shell = value(SHELL);
  816.         if (Shell == NOSTR)
  817.             Shell = "/bin/sh";
  818.         close(pivec[0]);
  819.         close(1);
  820.         dup(pivec[1]);
  821.         close(pivec[1]);
  822.         close(2);
  823.         shell_uid();
  824.         execl(Shell, Shell, "-c", cmdbuf, 0);
  825.         _exit(1);
  826.     }
  827.     if (pid == -1) {
  828.         perror("fork");
  829.         close(pivec[0]);
  830.         close(pivec[1]);
  831.         return(NOSTR);
  832.     }
  833.     close(pivec[1]);
  834.     l = read(pivec[0], xname, BUFSIZ);
  835.     close(pivec[0]);
  836.     while (wait(&s) != pid);
  837.         ;
  838.     s &= 0377;
  839.     if (s != 0 && s != SIGPIPE) {
  840.         fprintf(stderr, "\"Echo\" failed\n");
  841.         return(NOSTR);
  842.     }
  843.     if (l < 0) {
  844.         perror("read");
  845.         return(NOSTR);
  846.     }
  847.     if (l == 0) {
  848.         fprintf(stderr, "\"%s\": No match\n", name);
  849.         return(NOSTR);
  850.     }
  851.     if (l == BUFSIZ) {
  852.         fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
  853.         return(NOSTR);
  854.     }
  855.     xname[l] = 0;
  856.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  857.         ;
  858.     *++cp = '\0';
  859.     return(xname);
  860. }
  861.  
  862. /*
  863.  * Are any of the characters in the two strings the same?
  864.  */
  865.  
  866. anyof(s1, s2)
  867.     register char *s1, *s2;
  868. {
  869.     register int c;
  870.  
  871.     while (c = *s1++)
  872.         if (any(c, s2))
  873.             return(1);
  874.     return(0);
  875. }
  876.